﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Godot.core
{
    public class StringName
    {
        protected const int STRING_TABLE_BITS = 12;
		protected const int STRING_TABLE_LEN = 1 << STRING_TABLE_BITS;
        protected const int STRING_TABLE_MASK = STRING_TABLE_LEN - 1;

        protected class InnerData
        {
            public string name;
            public int hash;
            public int idx;
            
            public InnerData next;
            public InnerData prev;

            public InnerData()
            {
                next = prev = null;
            }
        }

        protected static bool _configured = false;
        protected static InnerData[] _table = new InnerData[STRING_TABLE_LEN];

        protected InnerData _data;

        public StringName()
        {
            _data = null;
        }

        public StringName(string p_arg)
        {
            _data = null;

	        if( p_arg == null || p_arg.Length == 0)
                return;	
	
	        int hash = p_arg.GetHashCode();
	
	        uint idx = (uint)(hash & STRING_TABLE_MASK);
	
	        _data = _table[idx];
	
	        while(_data != null) 
            {	
		        // compare hash first
		        if (_data.name.GetHashCode() == hash && _data.name == p_arg)
			        break;
		        _data = _data.next;
	        }


	        if (_data != null)
			      return;

	        _data = new InnerData();
	        _data.name = p_arg;
            _data.idx = (int)idx;
	        _data.next = _table[idx];
	        _data.prev = null;
	        if (_table[idx] != null)
		        _table[idx].prev = _data;
	        _table[idx]=_data;
        }

        public static implicit operator StringName(String p_arg)
        {
            if (p_arg == null) return null;
            return new StringName(p_arg);
        }

        public static implicit operator String(StringName p_arg)
        {
            return p_arg._data.name; ;
        }

        public static void setup()
        {
            if (_configured) return;
            for (int i = 0; i < STRING_TABLE_LEN; i++)
            {
                _table[i] = null;
            }
            _configured = true;
        }

        public static StringName search(String p_name)
        {
            return null;
        }

        public override bool Equals(object obj)
        {
            if (obj is StringName)
            {
                return _data.name == (obj as StringName)._data.name;
            }
            return false;
        }

        public override int GetHashCode()
        {
            return _data.name.GetHashCode();
        }
    }
}
